package org.batatasframework.bytecode;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.asm.ClassWriter;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.util.Assert;

public abstract class AbstractClassMaker extends ClassWriter implements Opcodes{

	protected final Log logger = LogFactory.getLog(getClass());
	
	protected String signature;
	protected ClassAsminfo classInfo;
	protected ClassAsminfo parentInfo;
	
	protected final String[] interfaces;
	protected final Class<?>[] sourceInterfaces;
	
	public AbstractClassMaker(Class<?>... interfaces) {
		super(ClassWriter.COMPUTE_MAXS);
		if(null != interfaces){
			this.sourceInterfaces = interfaces;
			this.interfaces = new String[interfaces.length];
		}else{
			this.sourceInterfaces = null;
			this.interfaces = null;
		}
	}
	
	/** 被分配的一个字段 */
	protected class AssignField{
		protected String name;
		protected String desc;
	}
	
	protected class InternalMakeEvent{
		protected final MethodVisitor constructor;
		
		public InternalMakeEvent(MethodVisitor constructor){
			this.constructor = constructor;
		}
	}
	
	protected void _make(InternalMakeEvent imEvent)throws Exception{}
	
	public Class<?> make()throws Exception{
		Assert.notNull(classInfo, "被创建的目标对象不允许为空！");
		Assert.notNull(parentInfo, "目标对象的父类不允许为空!");
		
		visit(V1_6, ACC_PUBLIC, 
				classInfo.getClassPath(), signature, 
				parentInfo.getClassPath(), interfaces);
		
		MethodVisitor constructor = visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 
        // 代码开始：必须  
        constructor.visitCode();  
        constructor.visitVarInsn(ALOAD, 0);  
        constructor.visitMethodInsn(INVOKESPECIAL, parentInfo.getClassPath(), "<init>", "()V", false); 
        
        InternalMakeEvent imEvent = new InternalMakeEvent(constructor);
        _make(imEvent);
        
        constructor.visitInsn(RETURN);  
        constructor.visitMaxs(0, 0);// 计算栈和局部变量最大空间：必须  
        constructor.visitEnd();// 代码结束：必须  
        
		visitEnd();
		logger.info("动态生成类：" + classInfo.getClassName());
		return null;
	}
}
